package com.qd.flow.service.bill;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.cdqidi.exception.ApiException;
import com.qd.common.flow.constant.FlowConstants;
import com.qd.common.flow.domain.approval.ApprovalDTO;
import com.qd.common.flow.domain.approval.FlowDTO;
import com.qd.common.flow.domain.bill.FlowBillDTO;
import com.qd.common.flow.domain.bill.FlowHisTaskDTO;
import com.qd.common.flow.domain.bill.FlowTaskDTO;
import com.qd.common.flow.domain.config.FlowProcessNodeDTO;
import com.qd.common.flow.domain.event.FlowTaskStateDTO;
import com.qd.common.flow.enums.FlowEventType;
import com.qd.common.sys.util.SecurityUtils;
import com.qd.flow.listener.FlowListener;
import com.qd.flow.manager.FlowListenerManager;
import com.qd.flow.model.config.FlowProcessConfig;
import com.qd.flow.service.config.FlowProcessConfigService;
import com.qd.flow.service.config.FlowProcessNodeService;
import com.qd.system.service.org.OrgService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * 〈一句话功能简述〉<br>
 *
 * @author sjk
 * @create 2024-02-21 13:37
 * @since 1.0.0
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class FlowService {
    private final FlowProcessConfigService flowProcessConfigService;
    private final FlowProcessNodeService flowProcessNodeService;
    private final FlowBillService flowBillService;
    private final FlowTaskService flowTaskService;
    private final FlowHisTaskService flowHisTaskService;
    private final OrgService orgService;

    /**
     * 创建流程
     *
     * @param flowDTO 流程参数
     */
    public void createFlow(FlowDTO flowDTO) {
        log.info("创建流程,流程编码: {}", flowDTO.getProcessCode());
        FlowProcessConfig flowProcessConfig = Optional.ofNullable(flowProcessConfigService.getUniqueByProcessCode(flowDTO.getProcessCode())).orElseThrow(() -> new ApiException("流程编码值错误"));
        FlowBillDTO flowBillDTO = flowBillService.getRunning(flowDTO.getBid(), flowProcessConfig.getProcessId(),flowDTO.getOperatorType());
        if (null == flowBillDTO) {
            flowBillDTO = new FlowBillDTO();
            flowBillDTO.setBillId(IdWorker.getIdStr());
            flowBillDTO.setProcessCode(flowDTO.getProcessCode());
            flowBillDTO.setProcessName(flowProcessConfig.getProcessName());
            flowBillDTO.setBid(flowDTO.getBid());
            flowBillDTO.setCreateTime(flowDTO.getCreateTime());
            flowBillDTO.setTaskName(flowDTO.getTaskName());
            flowBillDTO.setBillState(FlowConstants.BILL_STATE_0);
            flowBillDTO.setProcessUserName(flowDTO.getProcessUserName());
            flowBillDTO.setProcessOrgName(flowDTO.getProcessOrgName());
            flowBillDTO.setProcessId(flowProcessConfig.getProcessId());
            flowBillDTO.setOperatorType(flowDTO.getOperatorType());
            flowBillDTO.setProcessUserId(flowDTO.getProcessUserId());
            flowBillDTO.setProcessOrg(flowDTO.getProcessOrg());
            flowBillService.save(flowBillDTO);
        }
        FlowProcessNodeDTO flowProcessNode = flowProcessNodeService.getMinDTO(flowProcessConfig.getProcessId());
        if (null == flowProcessNode) {
            throw new ApiException("检查审批任务配置");
        }
        createFlowTask(flowBillDTO.getBillId(), flowDTO.getCreateTime(), flowProcessNode);
        flowBillDTO.freeData();
        flowProcessNode.freeData();
    }


    /**
     * 审批
     *
     * @param approvalDTO 审批信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void approval(ApprovalDTO approvalDTO, FlowTaskDTO flowTaskDTO, FlowBillDTO flowBillDTO) {
        FlowEventType flowEventType;
        if (approvalDTO.getApprovalState().equals(FlowConstants.APPROVAL_STATUS_1)) {
            //是否是最后一个节点
            if (Boolean.TRUE.equals(flowProcessNodeService.isLasNode(flowTaskDTO.getNodeId()))) {
                //通知结束
                flowBillDTO.setBillState(FlowConstants.BILL_STATE_1);
                flowBillDTO.setFinishTime(approvalDTO.getApprovalDate());
                flowBillService.update(flowBillDTO);
                flowEventType = com.qd.common.flow.enums.FlowEventType.FINISH;
            }else{
                //如果不是最后一个节点，那么创建下一个节点，并通知
                FlowProcessNodeDTO flowProcessNode = flowProcessNodeService.getNext(flowTaskDTO.getNodeId());
                if(null == flowProcessNode){
                    log.error("节点异常,上一节点ID： {}",flowTaskDTO.getNodeId());
                    throw new ApiException("节点异常");
                }
                createFlowTask(flowTaskDTO.getBillId(),approvalDTO.getApprovalDate(),flowProcessNode);
                flowProcessNode.freeData();
                flowEventType = com.qd.common.flow.enums.FlowEventType.NODE_FINISH;
            }
        } else if (approvalDTO.getApprovalState().equals(FlowConstants.APPROVAL_STATUS_2)) {
            //通知打回
            flowEventType = com.qd.common.flow.enums.FlowEventType.STOP;
        } else if (approvalDTO.getApprovalState().equals(FlowConstants.APPROVAL_STATUS_3)) {
            //终结以后结束流程
            flowBillDTO.setBillState(FlowConstants.BILL_STATE_1);
            flowBillDTO.setFinishTime(approvalDTO.getApprovalDate());
            flowBillService.update(flowBillDTO);
            flowEventType = com.qd.common.flow.enums.FlowEventType.FINISH;
        } else {
            log.error("审批状态值错误,ApprovalState: {}", approvalDTO.getApprovalState());
            throw new ApiException("审批状态值错误");
        }
        approvalDTO.setApproval(SecurityUtils.getLoginUser().getUserId());
        approvalDTO.setApprovalName(SecurityUtils.getLoginUser().getUsername());
        approvalDTO.setApprovalOrg(SecurityUtils.getLoginUser().getCurrentOrgId());
        approvalDTO.setApprovalOrgName(orgService.idToDisplay(SecurityUtils.getLoginUser().getCurrentOrgId()));
        //保存历史记录
        saveHisTask(approvalDTO, flowBillDTO, flowTaskDTO);
        //发送事件通知
        sendEvent(flowBillDTO, approvalDTO, flowEventType);

        flowTaskService.removeById(approvalDTO.getTaskId());
        flowTaskDTO.freeData();
        flowBillDTO.freeData();
    }

    private void sendEvent(FlowBillDTO flowBillDTO, ApprovalDTO approvalDTO, com.qd.common.flow.enums.FlowEventType flowEventType) {
        FlowTaskStateDTO flowTaskStateDTO = new FlowTaskStateDTO();
        flowTaskStateDTO.setProcessCode(flowBillDTO.getProcessCode());
        flowTaskStateDTO.setOperatorType(flowBillDTO.getOperatorType());
        flowTaskStateDTO.setBid(flowBillDTO.getBid());
        flowTaskStateDTO.setFlowEventType(flowEventType);
        flowTaskStateDTO.setApprovalStatus(approvalDTO.getApprovalState());
        flowTaskStateDTO.setApprovalTime(approvalDTO.getApprovalDate());
        flowTaskStateDTO.setExtendJson(approvalDTO.getExtendJson());
        //使用同步模式
//        SpringContextHolder.publishEvent(new ApprovalStateEvent(flowTaskStateDTO));
        FlowListener flowListener = FlowListenerManager.getInstance().getFlowListener();
        if (null != flowListener) {
            flowListener.notify(() -> flowTaskStateDTO);
        }
        flowTaskStateDTO.freeData();
    }


    private void saveHisTask(ApprovalDTO approvalDTO, FlowBillDTO flowBillDTO, FlowTaskDTO flowTaskDTO) {
        FlowHisTaskDTO flowHisTaskDTO = new FlowHisTaskDTO();
        flowHisTaskDTO.setBid(flowBillDTO.getBid());
        flowHisTaskDTO.setAddTime(approvalDTO.getApprovalDate());
        flowHisTaskDTO.setStatus(approvalDTO.getApprovalState());
        if (approvalDTO.getApprovalState().equals(FlowConstants.APPROVAL_STATUS_1)) {
            flowHisTaskDTO.setResult(StringUtils.hasLength(approvalDTO.getApprovalResult()) ? approvalDTO.getApprovalResult() : "审核通过");
        } else {
            flowHisTaskDTO.setResult(approvalDTO.getApprovalResult());
        }
        flowHisTaskDTO.setNodeName(flowTaskDTO.getNodeName());
        flowHisTaskDTO.setApprovalName(approvalDTO.getApprovalName());
        flowHisTaskDTO.setApprovalOrgName(approvalDTO.getApprovalOrgName());
        flowHisTaskDTO.setApprovalDepartName(flowTaskDTO.getApprovalDepartName());
        flowHisTaskDTO.setBillId(flowBillDTO.getBillId());
        flowHisTaskDTO.setApproval(approvalDTO.getApproval());
        flowHisTaskDTO.setApprovalOrg(approvalDTO.getApprovalOrg());
        flowHisTaskDTO.setNodeId(flowTaskDTO.getNodeId());
        flowHisTaskDTO.setProcessId(flowTaskDTO.getProcessId());
        flowHisTaskDTO.setApprovalDepart(flowTaskDTO.getApprovalDepart());
        flowHisTaskDTO.setOperatorType(flowBillDTO.getOperatorType());
        flowHisTaskService.save(flowHisTaskDTO);
        flowHisTaskDTO.freeData();
    }

    private void createFlowTask(String billId, LocalDateTime now, FlowProcessNodeDTO flowProcessNode) {
        FlowTaskDTO flowTaskDTO = new FlowTaskDTO();
        flowTaskDTO.setCreateTime(now);
        flowTaskDTO.setNodeName(flowProcessNode.getNodeName());
        flowTaskDTO.setApprovalDepart(flowProcessNode.getApprovalDepart());
        flowTaskDTO.setApprovalDepartName(flowProcessNode.getApprovalDepartDisplay());
        flowTaskDTO.setBillId(billId);
        flowTaskDTO.setNodeId(flowProcessNode.getNodeId());
        flowTaskDTO.setProcessId(flowProcessNode.getProcessId());
        flowTaskService.save(flowTaskDTO);
        flowProcessNode.freeData();
    }

    @Transactional(rollbackFor = Exception.class)
    public void removeTaskByBid(String projectId, String operatorType) {
        List<String> taskIds = flowTaskService.getBaseMapper().getTaskId(projectId, operatorType);
        if (null != taskIds && !taskIds.isEmpty()) {
            flowTaskService.removeByIds(taskIds);
        }
    }
}